#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

#include <iostream>
#include <stack>
#include <string>

using namespace std;

const static char *WORDS[] = {
    "contrive", "hum",          "imperil", "lade",   "addition",
    "blow",     "chance",       "mouth",   "pocket", "punishment",
    "rest",     "adjoining",    "alive",   "brown",  "feeble",
    "jolly",    "parsimonious", "sweet",   "tawdry", "verdant",
};

static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static stack<string> st;

void *read_handler(void *name) {
  for (int i = 0; i < 5; ++i) {
    // 上锁
    pthread_mutex_lock(&lock);
    if (st.empty()) {
      // 如果资源不足则阻塞，等待生产者生产完毕信号发出后恢复
      pthread_cond_wait(&cond, &lock);
    }
    string str = st.top();
    st.pop();
    printf("[READ %s] <- %s\n", (char *)name, str.c_str());
    // 解锁
    pthread_mutex_unlock(&lock);
  }
  cout << "[" << (char *)name << " SUB READ FINISH]" << endl;
  fflush(NULL);
  return nullptr;
}

void *write_handler(void *name) {
  for (int i = 0; i < 10; ++i) {
    pthread_mutex_lock(&lock);
    string str = WORDS[rand() % 20];
    st.push(str);
    printf("[WRITE %s] -> %s\n", (char *)name, str.c_str());
    // 广播唤醒所有等待线程（适用1生产者：n消费者，生产者能一次产生多个产品的情况）
    pthread_cond_broadcast(&cond);
    // 至少唤醒一个等待线程
    // pthread_cond_signal(&cond);
    pthread_mutex_unlock(&lock);
  }
  cout << "[" << (char *)name << " SUB WRITE FINISH]" << endl;
  fflush(NULL);
  return nullptr;
}

int main(int argc, char const *argv[]) {
  srand(time(NULL));
  pthread_t t1, t2, t3;
  pthread_create(&t1, NULL, write_handler, (void *)"produce");
  pthread_create(&t2, NULL, read_handler, (void *)"custmer1");
  pthread_create(&t3, NULL, read_handler, (void *)"custmer2");
  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  pthread_join(t3, NULL);

  pthread_mutex_destroy(&lock);
  pthread_cond_destroy(&cond);
  return 0;
}
